import {
	checkAllCart,
	deleteCart,
	findCart,
	getNewCartGoods,
	insertCart,
	mergeCart,
	updateCartImmediate,
} from '@/network/cart'

// 购物车模块
export default {
	namespaced: true,
	// state======================
	state() {
		return {
			/**
			 * 购物车商品列表
			 * 约定本地存储的信息内容 - 字段名可参考购物车列表接口的字段名
			 * id name picture price count skuId attrsText selected
			 * nowPrice stock isCollect discount isEffective
			 *
			 * 未登录  操作本地 list
			 * 已登陆  操作API--actions--updateCart--findCart--commit('setCart')
			 * 相当于  清空后赋值最新的购物车数据
			 */
			list: [],
		}
	},
	// mutations========================
	// 修改 state 的函数
	mutations: {
		// 加入购物车
		insertCart(state, payLoad) {
			/**
			 *  情况1：已经添加过的商品(skuId已存在)，是数量的累加
			 *  记录 count 删除之前的    添加到最前
			 *  情况2：没有添加过的就     添加到列表前
			 *  skuID 为 库存唯一标识   id 为商品id 可能有多个
			 */
			const index = state.list.findIndex(item => item.skuId === payLoad.skuId)
			// -1 没找到  >=0 为数组索引
			if (index > -1) {
				const count = state.list[index].count
				state.list.splice(index, 1)
				payLoad.count += count
			}
			state.list.unshift(payLoad)
		},

		// 更新修改购物车商品对象(时间久了本地购物车 部分会失效改变)
		updateCart(state, good) {
			/**
			 *  对象合并
			 * 1 需要创建新的对象接收   属性相同  后面会覆盖前面
			 * const newObj = { ...obj1, ...obj2 };
			 * 2 Object.assign() (最推荐)
			 * 一个目标对象和一个或者多个源对象作为参数  属性相同  后面会覆盖前面
			 * Object.assign(target, obj2);
			 * 3 const newObj = JSON.parse(JSON.stringify(obj))
			 *
			 * 本地对象 只修改传进来的合格属性 库存 价格  是否选中(未选中false为有效数据) 等等
			 * 此处需要 剔除 不合格的属性  所以循环遍历
			 */
			// 1根据 skuId 找到 对应的 之前Vuex good
			const LocalGood = state.list.find(v => v.skuId === good.skuId)
			for (const key in good) {
				if (good[key] !== undefined && good[key] !== '' && good[key] !== null) {
					LocalGood[key] = good[key]
				}
			}
		},

		// 删除购物车 某个商品 skuId
		deleteCart(state, skuId) {
			// 根据索引删除 该商品
			const index = state.list.findIndex(good => good.skuId === skuId)
			state.list.splice(index, 1)
		},

		// 批量设置购物车信息   --清空 [] --获取新数据 [Object]
		setCart(state, payLoad) {
			state.list = payLoad
		},
	},
	// actions=============================
	// 做异步操作的函数
	actions: {
		// 加入购物车
		insertCart(context, payLoad) {
			// 返回 Promise  在调用 dispatch 后可通过 then
			return new Promise((resolve, reject) => {
				// 1 判断是否登陆 rootState user--token
				if (context.rootState.user.profile.token) {
					// 登陆状态
					// 1 调用接口 传入服务器  解构出{ skuId, count }
					const { skuId, count } = payLoad
					insertCart(skuId, count).then(() => {
						// 2 成功后 updateCart() 获取最新的购物车列表
						context.dispatch('updateCart')
					})
				} else {
					// 未登录
					context.commit('insertCart', payLoad)
				}
				resolve('加入购物车成功')
			})
		},

		// 更新修改购物车商品对象(时间久了本地购物车 部分会失效改变)
		// 登陆后 获取最新购物车列表
		async updateCart({ rootState, state, commit }) {
			/**
			 *  判断是否登陆
			 *  同时发送请求(本地 good.skuId),等所有请求成功,一并修改本地数据
			 *  Promise.all([])  返回结果 为数组  且和 传入数组一一对应
			 */
			if (rootState.user.profile.token) {
				// result为获取的 购物车列表  setCart 更新列表
				const { result } = await findCart()
				commit('setCart', result)
			} else {
				const apiArray = state.list.map(good => getNewCartGoods(good.skuId))
				const goodList = await Promise.all(apiArray)
				goodList.forEach(({ result }, index) => {
					// 返回数据没有 skuId 根据索引 获取
					commit('updateCart', { skuId: state.list[index].skuId, ...result })
				})
			}
			return '更新本地购物车成功'
		},

		// 更新修改购物车商品对象--直接本地修改 不通过API
		// good为对象 必须有 skuId  selected count
		// 该商品存在只是修改属性  这里登录状态 做本地操作
		async updateCartImmediate({ rootState, dispatch, commit }, good) {
			if (rootState.user.profile.token) {
				// 1 修改购物车商品API 2 updateCart() 获取最新的购物车列表
				await updateCartImmediate(good)
				// await dispatch('updateCart')
				commit('updateCart', good)
			} else {
				commit('updateCart', good)
			}
			return '修改购物车成功'
		},

		// 删除购物车 某个商品 skuId
		async deleteCart({ rootState, dispatch, commit }, skuId) {
			if (rootState.user.profile.token) {
				// 1 删除API 2 updateCart() 获取最新的购物车列表
				await deleteCart([skuId])
				await dispatch('updateCart')
			} else {
				commit('deleteCart', skuId)
			}
			return '商品删除成功'
		},

		// 批量删除购物车 -- false 为选中  true 为失效商品
		async batchDeleteCart({ rootState, getters, dispatch, commit }, parameter) {
			const List = parameter ? getters.invalidList : getters.selectedList
			if (List.length === 0) return Promise.reject(new Error('无需操作'))
			if (rootState.user.profile.token) {
				// 1 删除API 2 updateCart() 获取最新的购物车列表
				const ids = List.map(good => good.skuId)
				await deleteCart(ids)
				await dispatch('updateCart')
			} else {
				List.forEach(v => commit('deleteCart', v.skuId))
			}
			return `全部${parameter ? '清空无效列表' : '删除操作'}成功`
		},

		// 全选按钮操作
		async checkCartAll({ rootState, getters, dispatch, commit }, selected) {
			const validList = getters.validList
			if (rootState.user.profile.token) {
				// 1 全部选中&取消API 2 updateCart() 获取最新的购物车列表
				const ids = validList.map(good => good.skuId)
				await checkAllCart(ids, selected)
				await dispatch('updateCart')
			} else {
				// 遍历 有效列表 使其 selected 与 payLoad 一致
				validList.forEach(good =>
					commit('updateCart', { skuId: good.skuId, selected })
				)
			}
			return '全选操作成功'
		},

		/**
		 *  购物车 sku组件修改规格
		 *  1 参数  当前 skuId  修改后的对象
		 *  2 通过skuId 查到之前的 good
		 *  3 通过 skuId 将其删除
		 *  4 记录 它的 id 名字 主图 数量 是否选中 等  初始化需要 手动添加的 属性
		 *   注意  stock-->inventory attrsText-->specsText nowPrice--price>字段
		 *  5 将 修改后的对象 与其合并 覆盖 重复属性 skuId inventory oldPrice price specsText
		 *  注意  数量 count 来自 oldGood
		 *  6 insertCart
		 */
		async updateCartSku({ rootState, state, dispatch, commit }, arr) {
			const oldGood = state.list.find(v => v.skuId === arr[0])
			if (rootState.user.profile.token) {
				// 1 删除API  2 添加新商品到购物车 insertCart--API
				// 3 updateCart() 获取最新的购物车列表
				await deleteCart([oldGood.skuId])
				await insertCart(arr[1].skuId, oldGood.count)
				await dispatch('updateCart')
			} else {
				const newGood = {
					...oldGood,
					...arr[1],
					stock: arr[1].inventory,
					attrsText: arr[1].specsText,
					nowPrice: arr[1].price,
				}
				commit('deleteCart', arr[0])
				commit('insertCart', newGood)
			}
			return '修改成功'
		},

		/**
		 * 合并购物车--此时肯定已经登陆
		 * 登陆成功后  要合并本地购物车  与线上购物车
		 * 1 账号 或者手机号 登陆 成功处  LoginForm.vue
		 * 2 QQ 号直接登陆处  login-callback-index
		 * 3 QQ 登陆  绑定手机号处  login-callback-CallBackBind
		 * 4 QQ 登陆  完善信息处    login-callback-CallBackPatch
		 * 2-3-4-->useQQLoginSavePush
		 *
		 * 1 上传本地购物车信息到服务器
		 * 2 清空本地购物车信息
		 * 3 退出登陆时 要清空本地购物车信息
		 * 4 获取 服务器 购物车列表(updateCart 登陆状态获取)
		 */
		async mergeCart({ state, commit }) {
			// 获取本地购物车  信息 数组
			const arrayList = state.list.map(good => {
				return { skuId: good.skuId, selected: good.selected, count: good.count }
			})
			// 上传服务器
			await mergeCart(arrayList)
			// 成功  删除本地购物车信息
			commit('setCart', [])
			return '合并本地购物车成功'
		},
	},
	// getters========================
	// vuex的计算属性  组件中直接 state不是响应式  可以computed包裹
	getters: {
		// 有效商品列表
		validList(state) {
			// 商品 有库存 并且 有效
			return state.list.filter(v => v.stock && v.isEffective)
		},

		// 有效商品件数 购物车图标显示
		validTotal(state, getters) {
			return getters.validList.length
		},

		// 有效商品总件数 item.count
		validTotalCount(state, getters) {
			return getters.validList.reduce((p, c) => p + c.count, 0)
		},

		// 有效商品总金额
		// js 浮点数 计算不准确 一般 都是先 X 100 倍 Math.round转为整数 计算完 在 / 100
		validTotalPrice(state, getters) {
			return (
				getters.validList.reduce(
					(p, c) => p + Math.round(c.nowPrice * 100) * c.count,
					0
				) / 100
			)
		},

		// 无效商品列表
		invalidList(state) {
			return state.list.filter(v => !v.stock || !v.isEffective)
		},

		// 已选商品列表  有效列表中  selected true
		selectedList(state, getters) {
			return getters.validList.filter(v => v.selected)
		},

		// 已选商品总件数
		selectedTotalCount(state, getters) {
			return getters.selectedList.reduce((p, c) => p + c.count, 0)
		},

		// 已选商品总金额
		selectedTotalPrice(state, getters) {
			return (
				getters.selectedList.reduce(
					(p, c) => p + Math.round(c.nowPrice * 100) * c.count,
					0
				) / 100
			)
		},

		// 是否全选  1 有效商品列表 > 0 2 有效商品列表总数===选中商品列表总数
		isCheckedAll(state, getters) {
			return (
				getters.validList.length > 0 &&
				getters.validList.length === getters.selectedList.length
			)
		},
	},
}
